在介紹完 Error 之後,還記得我們的 JWT 嗎? 幫大家回顧一下 ~
我們在 Auth Controller 中做了一個 protect function:
protect function:
exports.protect = async (req, res, next) => {
// 1. 取得 token
let token;
// 此處會依照開頭是否是 Bearer 來作為判斷依據的原因:
// 因為這邊預設 request 的 header 是帶上: "Bearer ${JWT_TOKEN}"
if(
req.headers.authentication &&
req.headers.autrhntication.startWith('Bearer')
) {
token = req.headers.authorization.split(' ')[1];
}
if (!token) {
return next (
new AppError('Please Log in to get access', 401);
);
}
// 2. 驗證 token
// 此處使用 promisify 是想要把 jwt.verify 轉換成 promise 版本,避免 Error first call-back
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);
// 3. 確認 user 是否還存在
const freshUser = await User.findById(decoded.id);
if(!freshUser) {
return next(new AppError('The token belonging to this user does no longer exist.', 401));
}
// 4. 確認是否在 token 發出去後,user 改動了 password
// 此處使用到的 changedPasswordAfter function 寫在下一個程式碼區塊
// 這邊的 iat 是指 指示 JWT 發佈時間的時間戳,有興趣可以回之前的規劃篇看看 ~
if (freshUser.changedPasswordAfter(decoded.iat)) {
return next(new AppError('Password has been changed recently. Please login again.', 401));
}
// 5. 允許進入被受保護的 route
req.user = freshUser;
next();
}
我們在這邊實作了:
在 Access 時,帶入的 signature 是錯誤的話,會噴出 name 為 'JsonWebTokenError' 的錯誤。
除此之外,我們還會遇到 token 過期的情形,這時我們就需要處理 'TokenExpiredError' 的錯誤。
而針對這些錯誤我們可以將它統一在 error Controller 中處理:
error controller:
module.exports = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
sendDevelopmentError(err, res);
} else if (process.env.NODE_ENV === 'prodcution') {
let error = { ...err };
// 處理 DB 相關的 error
if (error.name === 'CastError') error = handleCastErrorInDB(error);
// 此處省略處理其他 DB 相關的 error
// 此處處理 JWT 的 error
// JsonWebTokenError
if (error.name === 'JsonWebTokenError') error = handleJWTError(error);
// TokenExpiredError
if (error.name === 'TokenExpiredError') error = handleJWTExpiredError(error);
sendProductionError(err, res);
}
}
handleJWTError function:
const handleJWTError = err => new AppError('Invalid token, please log in again!', 401);
handleJWTExpiredError function:
const handleJWTExpiredError = err => new AppError('Your token has expired, please log in again!', 401);
今天的介紹就大概就到這邊~ 整合了先前介紹的 JWT & Error,接下來就會進到 reset password 啦~